﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NCalculator.Operations
{
    [Serializable()]
    public class MedianNode : ValueNode
    {
        #region Attributes
        private List<ValueNode> _list;
        #endregion

        public MedianNode()
        {
            _list = new List<ValueNode>();
        }

        /// <summary>
        /// Adds an element of with will be calculated median
        /// </summary>
        /// <param name="node"></param>
        public void AddElement(ValueNode node)
        {
            _list.Add(node);
        }

        /// <summary>
        /// Calculate mediana
        /// </summary>
        /// <returns>result of mediana</returns>
        public override double Evaluation()
        {
            if (_list.Count == 0) return 0;
            if (_list.Count == 1)
            {
                return _list[0].Evaluation();
            }

            double median = 0;
            _list.Sort(CompareValueNode);

            if ((_list.Count % 2) != 0)
            {
                int n = _list.Count;
                median = _list[(n) / 2].Evaluation();
            }
            else
            {
                int n = _list.Count / 2;
                double x1 = _list[n-1].Evaluation();
                double x2 = _list[n].Evaluation();
                median = (x1 + x2) / 2;
            }

            return median;
        }

        /// <summary>
        /// Convert mediane into string   
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();

            builder.Append("Med(");
            builder.Append(_list[0].ToString());
            for (int i = 1; i < _list.Count; i++)
            {
                builder.Append(", " + _list[i]);
            }
            builder.Append(") ");

            return builder.ToString();
        }

        /// <summary>
        /// Comparsion static method used for sorting list
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        private static int CompareValueNode(ValueNode left, ValueNode right)
        {
            if (left == null)
            {
                if (right == null)
                    return 0; // both are equal
                else
                    return -1; // right is greater
            }
            else
            {
                if (right == null)
                    return 1; // left are greater
                else // both are not null
                {
                    if (left.Evaluation() > right.Evaluation())
                        return 1;
                    else if (left.Evaluation() < right.Evaluation())
                        return -1;
                    else
                        return 0;
                }
            }
        }
    }
}
